////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2016-2017 Qualcomm Technologies, Inc.
// All Rights Reserved.
// Confidential and Proprietary - Qualcomm Technologies, Inc.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @file camxatomic.cpp
/// @brief Implementation of Atomic operations
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include "camxatomic.h"
#include "camxincs.h"

#if defined (_LINUX)            // Use gcc built-ins directly for Linux

CAMX_NAMESPACE_BEGIN

/// @todo (CAMX-31) - remove inline for now, figure out why inlining is giving linker error

// Use __sync built-ins for older versions of GCC,
#if __GNUC__ == 4 && __GNUC_MINOR__ < 7

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicInc
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT CamxAtomicInc(
    volatile INT* pVar)
{
    return (__sync_add_and_fetch(pVar, 1));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicIncU
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT CamxAtomicIncU(
    volatile UINT* pVar)
{
    return (__sync_add_and_fetch(pVar, 1));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicDec
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT CamxAtomicDec(
    volatile INT* pVar)
{
    return (__sync_sub_and_fetch(pVar, 1));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicDecU
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT CamxAtomicDecU(
    volatile UINT* pVar)
{
    return (__sync_sub_and_fetch(pVar, 1));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicAdd
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT CamxAtomicAdd(
    volatile INT*   pVar,
    INT             val)
{
    return (__sync_add_and_fetch(pVar, val));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicAdd8
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT8 CamxAtomicAdd8(
    volatile INT8*  pVar,
    INT8            val)
{
    return (__sync_add_and_fetch(pVar, val));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicAdd32
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT32 CamxAtomicAdd32(
    volatile INT32* pVar,
    INT32           val)
{
    return (__sync_add_and_fetch(pVar, val));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicAdd64
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT64 CamxAtomicAdd64(
    volatile INT64* pVar,
    INT64           val)
{
    return (__sync_add_and_fetch(pVar, val));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicAddU
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT CamxAtomicAddU(
    volatile UINT*  pVar,
    UINT            val)
{
    return (__sync_add_and_fetch(pVar, val));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicAddU8
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT8 CamxAtomicAddU8(
    volatile UINT8* pVar,
    UINT8           val)
{
    return (__sync_add_and_fetch(pVar, val));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicAddU32
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT32 CamxAtomicAddU32(
    volatile UINT32*    pVar,
    UINT32              val)
{
    return (__sync_add_and_fetch(pVar, val));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicAddU64
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT64 CamxAtomicAddU64(
    volatile UINT64*    pVar,
    UINT64              val)
{
    return (__sync_add_and_fetch(pVar, val));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicSub
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT CamxAtomicSub(
    volatile INT*   pVar,
    INT             val)
{
    return (__sync_sub_and_fetch(pVar, val));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicSub8
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT8 CamxAtomicSub8(
    volatile INT8*  pVar,
    INT8            val)
{
    return (__sync_sub_and_fetch(pVar, val));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicSub32
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT32 CamxAtomicSub32(
    volatile INT32* pVar,
    INT32           val)
{
    return (__sync_sub_and_fetch(pVar, val));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicSub64
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT64 CamxAtomicSub64(
    volatile INT64* pVar,
    INT64           val)
{
    return (__sync_sub_and_fetch(pVar, val));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicSubU8
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT CamxAtomicSubU(
    volatile UINT*  pVar,
    UINT            val)
{
    return (__sync_sub_and_fetch(pVar, val));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicSubU8
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT8 CamxAtomicSubU8(
    volatile UINT8* pVar,
    UINT8           val)
{
    return (__sync_sub_and_fetch(pVar, val));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicSubU32
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT32 CamxAtomicSubU32(
    volatile UINT32*    pVar,
    UINT32              val)
{
    return (__sync_sub_and_fetch(pVar, val));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicSubU64
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT64 CamxAtomicSubU64(
    volatile UINT64*    pVar,
    UINT64              val)
{
    return (__sync_sub_and_fetch(pVar, val));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicStore
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CamxAtomicStore(
    volatile INT*   pVar,
    INT             val)
{
    (VOID)__sync_lock_test_and_set(pVar, val);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicStore8
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CamxAtomicStore8(
    volatile INT8*  pVar,
    INT8            val)
{
    (VOID)__sync_lock_test_and_set(pVar, val);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicStore32
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CamxAtomicStore32(
    volatile INT32* pVar,
    INT32           val)
{
    (VOID)__sync_lock_test_and_set(pVar, val);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicStore64
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CamxAtomicStore64(
    volatile INT64* pVar,
    INT64           val)
{
    (VOID)__sync_lock_test_and_set(pVar, val);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicStoreU
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CamxAtomicStoreU(
    volatile UINT*  pVar,
    UINT            val)
{
    (VOID)__sync_lock_test_and_set(pVar, val);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicStoreU8
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CamxAtomicStoreU8(
    volatile UINT8* pVar,
    UINT8           val)
{
    (VOID)__sync_lock_test_and_set(pVar, val);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicStoreU32
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CamxAtomicStoreU32(
    volatile UINT32*    pVar,
    UINT32              val)
{
    (VOID)__sync_lock_test_and_set(pVar, val);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicStoreU64
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CamxAtomicStoreU64(
    volatile UINT64*    pVar,
    UINT64              val)
{
    (VOID)__sync_lock_test_and_set(pVar, val);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicStoreP
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CamxAtomicStoreP(
    VOID** ppDst,
    VOID*  pSrc)
{
#if _LP64
    CamxAtomicStoreU64(reinterpret_cast<UINT64*>(ppDst), reinterpret_cast<UINT64>(pSrc));
#else
    CamxAtomicStoreU32(reinterpret_cast<UINT32*>(ppDst), reinterpret_cast<UINT32>(pSrc));
#endif // _LP64
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicLoad
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT CamxAtomicLoad(
    volatile INT* pVar)
{
    return (__sync_add_and_fetch(pVar, 0));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicLoad8
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT8 CamxAtomicLoad8(
    volatile INT8* pVar)
{
    return (__sync_add_and_fetch(pVar, 0));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicLoad32
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT32 CamxAtomicLoad32(
    volatile INT32* pVar)
{
    return (__sync_add_and_fetch(pVar, 0));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicLoad64
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT64 CamxAtomicLoad64(
    volatile INT64* pVar)
{
    return (__sync_add_and_fetch(pVar, 0));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicLoadU
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT CamxAtomicLoadU(
    volatile UINT* pVar)
{
    return (__sync_add_and_fetch(pVar, 0));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicLoadU8
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT8 CamxAtomicLoadU8(
    volatile UINT8* pVar)
{
    return (__sync_add_and_fetch(pVar, 0));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicLoadU32
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT32 CamxAtomicLoadU32(
    volatile UINT32* pVar)
{
    return (__sync_add_and_fetch(pVar, 0));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicLoadU64
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT64 CamxAtomicLoadU64(
    volatile UINT64* pVar)
{
    return (__sync_add_and_fetch(pVar, 0));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicLoadP
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID* CamxAtomicLoadP(
    VOID** ppVar)
{
#if _LP64
    return reinterpret_cast<VOID*>((CamxAtomicLoadU64(reinterpret_cast<UINT64*>(ppVar))));
#else
    return reinterpret_cast<VOID*>((CamxAtomicLoadU32(reinterpret_cast<UINT32*>(ppVar))));
#endif // _LP64
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicCompareExchange
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL CamxAtomicCompareExchange(
    volatile INT*   pVar,
    INT             cmp,
    INT             newval)
{
    return (__sync_bool_compare_and_swap(pVar, cmp, newval));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicCompareExchangeU
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL CamxAtomicCompareExchangeU(
    volatile UINT*  pVar,
    UINT            cmp,
    UINT            newval)
{
    return (__sync_bool_compare_and_swap(pVar, cmp, newval));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxFence
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CamxFence()
{
    __sync_synchronize();
}

// else use __atomic builtins for newer and clang.
#else

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicInc
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT CamxAtomicInc(
    volatile INT* pVar)
{
    return (__atomic_add_fetch(pVar, 1, __ATOMIC_RELAXED));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicIncU
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT CamxAtomicIncU(
    volatile UINT* pVar)
{
    return (__atomic_add_fetch(pVar, 1, __ATOMIC_RELAXED));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicDec
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT CamxAtomicDec(
    volatile INT* pVar)
{
    return (__atomic_sub_fetch(pVar, 1, __ATOMIC_RELAXED));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicDecU
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT CamxAtomicDecU(
    volatile UINT* pVar)
{
    return (__atomic_sub_fetch(pVar, 1, __ATOMIC_RELAXED));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicAdd8
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT CamxAtomicAdd(
    volatile INT*   pVar,
    INT             val)
{
    return (__atomic_add_fetch(pVar, val, __ATOMIC_RELAXED));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicAdd8
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT8 CamxAtomicAdd8(
    volatile INT8*  pVar,
    INT8            val)
{
    return (__atomic_add_fetch(pVar, val, __ATOMIC_RELAXED));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicAdd32
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT32 CamxAtomicAdd32(
    volatile INT32* pVar,
    INT32           val)
{
    return (__atomic_add_fetch(pVar, val, __ATOMIC_RELAXED));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicAdd64
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT64 CamxAtomicAdd64(
    volatile INT64* pVar,
    INT64           val)
{
    return (__atomic_add_fetch(pVar, val, __ATOMIC_RELAXED));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicAddU
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT CamxAtomicAddU(
    volatile UINT*  pVar,
    UINT            val)
{
    return (__atomic_add_fetch(pVar, val, __ATOMIC_RELAXED));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicAddU8
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT8 CamxAtomicAddU8(
    volatile UINT8* pVar,
    UINT8           val)
{
    return (__atomic_add_fetch(pVar, val, __ATOMIC_RELAXED));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicAddU32
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT32 CamxAtomicAddU32(
    volatile UINT32*    pVar,
    UINT32              val)
{
    return (__atomic_add_fetch(pVar, val, __ATOMIC_RELAXED));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicAddU64
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT64 CamxAtomicAddU64(
    volatile UINT64*    pVar,
    UINT64              val)
{
    return (__atomic_add_fetch(pVar, val, __ATOMIC_RELAXED));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicSub
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT CamxAtomicSub(
    volatile INT*   pVar,
    INT             val)
{
    return (__atomic_sub_fetch(pVar, val, __ATOMIC_RELAXED));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicSub8
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT8 CamxAtomicSub8(
    volatile INT8*  pVar,
    INT8            val)
{
    return (__atomic_sub_fetch(pVar, val, __ATOMIC_RELAXED));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicSub32
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT32 CamxAtomicSub32(
    volatile INT32* pVar,
    INT32           val)
{
    return (__atomic_sub_fetch(pVar, val, __ATOMIC_RELAXED));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicSub64
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT64 CamxAtomicSub64(
    volatile INT64* pVar,
    INT64           val)
{
    return (__atomic_sub_fetch(pVar, val, __ATOMIC_RELAXED));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicSubU
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT CamxAtomicSubU(
    volatile UINT*  pVar,
    UINT            val)
{
    return (__atomic_sub_fetch(pVar, val, __ATOMIC_RELAXED));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicSubU8
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT8 CamxAtomicSubU8(
    volatile UINT8* pVar,
    UINT8           val)
{
    return (__atomic_sub_fetch(pVar, val, __ATOMIC_RELAXED));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicSubU32
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT32 CamxAtomicSubU32(
    volatile UINT32*    pVar,
    UINT32              val)
{
    return (__atomic_sub_fetch(pVar, val, __ATOMIC_RELAXED));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicSubU64
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT64 CamxAtomicSubU64(
    volatile UINT64*    pVar,
    UINT64              val)
{
    return (__atomic_sub_fetch(pVar, val, __ATOMIC_RELAXED));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicStore
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CamxAtomicStore(
    volatile INT*   pVar,
    INT             val)
{
    (VOID)__atomic_store_n(pVar, val, __ATOMIC_RELAXED);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicStore8
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CamxAtomicStore8(
    volatile INT8*  pVar,
    INT8            val)
{
    (VOID)__atomic_store_n(pVar, val, __ATOMIC_RELAXED);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicStore32
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CamxAtomicStore32(
    volatile INT32* pVar,
    INT32           val)
{
    (VOID)__atomic_store_n(pVar, val, __ATOMIC_RELAXED);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicStore64
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CamxAtomicStore64(
    volatile INT64* pVar,
    INT64           val)
{
    (VOID)__atomic_store_n(pVar, val, __ATOMIC_RELAXED);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicStoreU
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CamxAtomicStoreU(
    volatile UINT*  pVar,
    UINT            val)
{
    (VOID)__atomic_store_n(pVar, val, __ATOMIC_RELAXED);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicStoreU8
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CamxAtomicStoreU8(
    volatile UINT8* pVar,
    UINT8           val)
{
    (VOID)__atomic_store_n(pVar, val, __ATOMIC_RELAXED);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicStoreU32
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CamxAtomicStoreU32(
    volatile UINT32*    pVar,
    UINT32              val)
{
    (VOID)__atomic_store_n(pVar, val, __ATOMIC_RELAXED);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicStoreU64
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CamxAtomicStoreU64(
    volatile UINT64*    pVar,
    UINT64              val)
{
    (VOID)__atomic_store_n(pVar, val, __ATOMIC_RELAXED);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicStoreP
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CamxAtomicStoreP(
    VOID** ppDst,
    VOID*  pSrc)
{
#if _LP64
    CamxAtomicStoreU64(reinterpret_cast<UINT64*>(ppDst), reinterpret_cast<UINT64>(pSrc));
#else
    CamxAtomicStoreU32(reinterpret_cast<UINT32*>(ppDst), reinterpret_cast<UINT32>(pSrc));
#endif // _LP64
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicLoad
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT CamxAtomicLoad(
    volatile INT* pVar)
{
    return (__atomic_load_n(pVar, __ATOMIC_RELAXED));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicLoad8
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT8 CamxAtomicLoad8(
    volatile INT8* pVar)
{
    return (__atomic_load_n(pVar, __ATOMIC_RELAXED));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicLoad32
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT32 CamxAtomicLoad32(
    volatile INT32* pVar)
{
    return (__atomic_load_n(pVar, __ATOMIC_RELAXED));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicLoad64
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT64 CamxAtomicLoad64(
    volatile INT64* pVar)
{
    return (__atomic_load_n(pVar, __ATOMIC_RELAXED));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicLoadU
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT CamxAtomicLoadU(
    volatile UINT* pVar)
{
    return (__atomic_load_n(pVar, __ATOMIC_RELAXED));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicLoadU8
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT8 CamxAtomicLoadU8(
    volatile UINT8* pVar)
{
    return (__atomic_load_n(pVar, __ATOMIC_RELAXED));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicLoadU32
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT32 CamxAtomicLoadU32(
    volatile UINT32* pVar)
{
    return (__atomic_load_n(pVar, __ATOMIC_RELAXED));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicLoadU64
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT64 CamxAtomicLoadU64(
    volatile UINT64* pVar)
{
    return (__atomic_load_n(pVar, __ATOMIC_RELAXED));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicLoadP
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID* CamxAtomicLoadP(
    VOID** ppVar)
{
#if _LP64
    return reinterpret_cast<VOID*>((CamxAtomicLoadU64(reinterpret_cast<UINT64*>(ppVar))));
#else
    return reinterpret_cast<VOID*>((CamxAtomicLoadU32(reinterpret_cast<UINT32*>(ppVar))));
#endif // _LP64
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicCompareExchange
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL CamxAtomicCompareExchange(
    volatile INT*   pVar,
    INT             oldVal,
    INT             newVal)
{
    return (__atomic_compare_exchange_n(pVar, &oldVal, newVal, true, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicCompareExchangeU
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL CamxAtomicCompareExchangeU(
    volatile UINT*  pVar,
    UINT            oldVal,
    UINT            newVal)
{
    return (__atomic_compare_exchange_n(pVar, &oldVal, newVal, true, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST));
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxFence
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CamxFence()
{
    __atomic_thread_fence(__ATOMIC_SEQ_CST);
}

#endif // __GNUC__ == 4 && __GNUC_MINOR__ < 7

CAMX_NAMESPACE_END

#else                           // For every other platform

#include "camxosutils.h"
#include "camxdebug.h"

CAMX_NAMESPACE_BEGIN

/// @todo (CAMX-29) - Consider using C++11 atomic operations
// Forward declaration of singleton Initialize routine
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Initialize
///
/// @brief  Returns a pointer to the global mutex, initializing it if necessary
///
/// @note   Since this atomic implementation relies on the static initialization of g_pMutex,
///         atomics will not work properly when used in other static initialization routines as there
///         is no ordering guarantee on which is initialized first.
///
/// @return A pointer to the global mutex object.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static Mutex* Initialize();

// Singleton global mutex for all atomic operations
static Mutex* g_pMutex = Initialize();

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Initialize
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static Mutex* Initialize()
{
    if (NULL == g_pMutex)
    {
#if CAMX_USE_MEMSPY
        g_pMutex = Mutex::CreateNoSpy("GlobalAtomic");
#else // CAMX_USE_MEMSPY
        g_pMutex = Mutex::Create("GlobalAtomic");
#endif // CAMX_USE_MEMSPY
    }

    return g_pMutex;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicInc
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT CamxAtomicInc(
    volatile INT* pVar)
{
    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        *pVar = *pVar + 1;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }

    return *pVar;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicIncU
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT CamxAtomicIncU(
    volatile UINT* pVar)
{
    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        *pVar = *pVar + 1;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }

    return *pVar;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicDec
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT CamxAtomicDec(
    volatile INT* pVar)
{
    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        *pVar = *pVar - 1;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }

    return *pVar;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicDecU
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT CamxAtomicDecU(
    volatile UINT* pVar)
{
    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        *pVar = *pVar - 1;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }

    return *pVar;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicAdd
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT CamxAtomicAdd(
    volatile INT*   pVar,
    INT             val)
{
    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        *pVar = *pVar + val;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }

    return *pVar;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicAdd8
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT8 CamxAtomicAdd8(
    volatile INT8*  pVar,
    INT8            val)
{
    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        *pVar = *pVar + val;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }

    return *pVar;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicAdd32
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT32 CamxAtomicAdd32(
    volatile INT32* pVar,
    INT32           val)
{
    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        *pVar = *pVar + val;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }

    return *pVar;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicAdd64
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT64 CamxAtomicAdd64(
    volatile INT64* pVar,
    INT64           val)
{
    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        *pVar = *pVar + val;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }

    return *pVar;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicAddU
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT CamxAtomicAddU(
    volatile UINT*  pVar,
    UINT            val)
{
    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        *pVar = *pVar + val;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }

    return *pVar;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicAddU8
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT8 CamxAtomicAddU8(
    volatile UINT8* pVar,
    UINT8           val)
{
    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        *pVar = *pVar + val;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }

    return *pVar;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicAddU32
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT32 CamxAtomicAddU32(
    volatile UINT32*    pVar,
    UINT32              val)
{
    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        *pVar = *pVar + val;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }

    return *pVar;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicAddU64
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT64 CamxAtomicAddU64(
    volatile UINT64*    pVar,
    UINT64              val)
{
    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        *pVar = *pVar + val;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }

    return *pVar;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicSub
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT CamxAtomicSub(
    volatile INT*   pVar,
    INT             val)
{
    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        *pVar = *pVar - val;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }

    return *pVar;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicSub8
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT8 CamxAtomicSub8(
    volatile INT8*  pVar,
    INT8            val)
{
    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        *pVar = *pVar - val;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }

    return *pVar;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicSub32
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT32 CamxAtomicSub32(
    volatile INT32* pVar,
    INT32           val)
{
    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        *pVar = *pVar - val;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }

    return *pVar;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicSub64
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT64 CamxAtomicSub64(
    volatile INT64* pVar,
    INT64           val)
{
    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        *pVar = *pVar - val;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }

    return *pVar;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicSubU
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT CamxAtomicSubU(
    volatile UINT*  pVar,
    UINT            val)
{
    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        *pVar = *pVar - val;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }

    return *pVar;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicSubU8
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT8 CamxAtomicSubU8(
    volatile UINT8* pVar,
    UINT8           val)
{
    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        *pVar = *pVar - val;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }

    return *pVar;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicSubU32
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT32 CamxAtomicSubU32(
    volatile UINT32*    pVar,
    UINT32              val)
{
    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        *pVar = *pVar - val;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }

    return *pVar;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicSubU64
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT64 CamxAtomicSubU64(
    volatile UINT64*    pVar,
    UINT64              val)
{
    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        *pVar = *pVar - val;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }

    return *pVar;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicStore
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CamxAtomicStore(
    volatile INT*   pVar,
    INT             val)
{
    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        *pVar = val;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicStore8
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CamxAtomicStore8(
    volatile INT8*  pVar,
    INT8            val)
{
    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        *pVar = val;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicStore32
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CamxAtomicStore32(
    volatile INT32* pVar,
    INT32           val)
{
    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        *pVar = val;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicStore64
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CamxAtomicStore64(
    volatile INT64* pVar,
    INT64           val)
{
    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        *pVar = val;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicStoreU
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CamxAtomicStoreU(
    volatile UINT*  pVar,
    UINT            val)
{
    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        *pVar = val;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicStoreU8
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CamxAtomicStoreU8(
    volatile UINT8* pVar,
    UINT8           val)
{
    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        *pVar = val;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicStoreU32
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CamxAtomicStoreU32(
    volatile UINT32*    pVar,
    UINT32              val)
{
    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        *pVar = val;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicStoreU64
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CamxAtomicStoreU64(
    volatile UINT64*    pVar,
    UINT64              val)
{
    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        *pVar = val;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicStoreP
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CamxAtomicStoreP(
    VOID** ppDst,
    VOID*  pSrc)
{
    CAMX_UNREFERENCED_PARAM(ppDst);
    CAMX_UNREFERENCED_PARAM(pSrc);

    CAMX_NOT_IMPLEMENTED();
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicLoad
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT CamxAtomicLoad(
    volatile INT* pVar)
{
    INT val = 0;

    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        val = *pVar;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }

    return val;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicLoad8
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT8 CamxAtomicLoad8(
    volatile INT8* pVar)
{
    INT8 val = 0;

    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        val = *pVar;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }

    return val;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicLoad32
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT32 CamxAtomicLoad32(
    volatile INT32* pVar)
{
    INT32 val = 0;

    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        val = *pVar;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }

    return val;
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicLoad64
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
INT64 CamxAtomicLoad64(
    volatile INT64* pVar)
{
    INT64 val = 0;

    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        val = *pVar;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }

    return val;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicLoadU
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT CamxAtomicLoadU(
    volatile UINT* pVar)
{
    UINT val = 0;

    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        val = *pVar;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }

    return val;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicLoadU8
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT8 CamxAtomicLoadU8(
    volatile UINT8* pVar)
{
    UINT8 val = 0;

    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        val = *pVar;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }

    return val;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicLoadU32
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT32 CamxAtomicLoadU32(
    volatile UINT32* pVar)
{
    UINT32 val = 0;

    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        val = *pVar;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }

    return val;
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicLoadU64
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
UINT64 CamxAtomicLoadU64(
    volatile UINT64* pVar)
{
    UINT64 val = 0;

    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        val = *pVar;
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }

    return val;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicLoadP
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID* CamxAtomicLoadP(
    VOID** ppVar)
{
    CAMX_UNREFERENCED_PARAM(ppVar);

    CAMX_NOT_IMPLEMENTED();

    return NULL;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicCompareExchange
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL CamxAtomicCompareExchange(
    volatile INT*   pVar,
    INT             oldVal,
    INT             newVal)
{
    BOOL newValWritten = FALSE;

    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        if (*pVar == oldVal)
        {
            *pVar = newVal;
            newValWritten = TRUE;
        }
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }

    return newValWritten;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxAtomicCompareExchangeU
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL CamxAtomicCompareExchangeU(
    volatile UINT*  pVar,
    UINT            oldVal,
    UINT            newVal)
{
    BOOL newValWritten = FALSE;

    if (g_pMutex != NULL)
    {
        g_pMutex->Lock();
        if (*pVar == oldVal)
        {
            *pVar = newVal;
            newValWritten = TRUE;
        }
        g_pMutex->Unlock();
    }
    else
    {
        CAMX_ASSERT_ALWAYS();
    }

    return newValWritten;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CamxFence
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
VOID CamxFence()
{
    CAMX_NOT_IMPLEMENTED();
}

CAMX_NAMESPACE_END

#endif // defined (_LINUX)
